#include "log.h"
#include <iostream>
#include <sstream>
#include <QDebug>
#include <QtMessageHandler>
#include <QFile>
#include <QDir>
#include <QDateTime>
#include <qjsondocument.h>
#include <qjsonobject.h>
#include <QThread>

using namespace std;

const int ConsoleFont::DEFAULT = 0; // 重置颜色设置
const int ConsoleFont::BOLD = 1; // 加粗
const int ConsoleFont::UN_BOLD = 2; // 去粗
const int ConsoleFont::UNDER_LINE = 4; // 下滑线
const int ConsoleFont::GLINT = 5; // 闪烁
const int ConsoleFont::INVERSE = 7;// 反色
const int ConsoleFont::BOLD_2 = 21; // 加粗
const int ConsoleFont::NORMAL = 22; // 正常
const int ConsoleFont::UN_UNDER_LINE = 24; // 去掉下滑线
const int ConsoleFont::STOP_GLINT = 25; // 停止闪烁
const int ConsoleFont::INVERSE_2 = 27;// 反色

const int ConsoleFont::FORE_GROUND_BLACK = 30;// 前景，黑色
const int ConsoleFont::FORE_GROUND_RED = 31;// 前景，红色
const int ConsoleFont::FORE_GROUND_GREEN = 32;// 前景，绿色
const int ConsoleFont::FORE_GROUND_ORANGE = 33;// 前景，黄色
const int ConsoleFont::FORE_GROUND_BLUE = 34; //前景，篮色
const int ConsoleFont::FORE_GROUND_PURPLE = 35; //前景，紫色
const int ConsoleFont::FORE_GROUND_CYAN = 36; //前景，青色
const int ConsoleFont::FORE_GROUND_WHITE = 37; //前景，白色

const int ConsoleFont::BACK_GROUND_BLACK = 40;// 背景，黑色
const int ConsoleFont::BACK_GROUND_RED = 41;// 背景，红色
const int ConsoleFont::BACK_GROUND_GREEN = 42;// 背景，绿色
const int ConsoleFont::BACK_GROUND_ORANGE = 43;// 背景，黄色
const int ConsoleFont::BACK_GROUND_BLUE = 44; //背景，篮色
const int ConsoleFont::BACK_GROUND_PURPLE = 45; //背景，紫色
const int ConsoleFont::BACK_GROUND_CYAN = 46; //背景，青色
const int ConsoleFont::BACK_GROUND_WHITE = 47; //背景，白色

// 设置控制台字体样式
const QString ConsoleFont::setConsoleFont(std::initializer_list<int> codes, QString msg)
{
    if(codes.size() == 0) {
        return msg;
    }
    QString codeStr = "";
    int i = 0;
    for (auto code: codes)
    {
        if(i == 0) {
            codeStr = QString::number(code);
        } else {
            codeStr = codeStr + ";" + QString::number(code);
        }
        i++;
    }
    return "\033[" + codeStr + "m" + msg + "\033[0m";
}

const QString Log::INFO_FORMAT_TIME = "%time"; // 格式化输出日期表示
const QString Log::INFO_FORMAT_LEVEL = "%level"; // 格式化输出日志级别表示
const QString Log::INFO_FORMAT_CODE_FILE = "%file"; // 格式化输出代码文件地址表示
const QString Log::INFO_FORMAT_CODE_LINE = "%line"; // 格式化输出代码所在行表示
const QString Log::INFO_FORMAT_CODE_FUNCTION = "%function"; // 格式化输出代码所在方法函数表示
const QString Log::INFO_FORMAT_CODE_MSG = "%msg"; // 格式化输出代码打印内容表示
const QString Log::INFO_FORMAT_THREAD = "%thread"; // 格式化输出线程地址表示

QMap<QtMsgType,QPair<QString, LogOutType>> Log::msgTypeMap = Log::initMsgTypeMap(); // 日志类型与日志标识、输出类型映射
QMap<QtMsgType,std::initializer_list<int>> Log::levelFontMap = Log::initLevelFonts(); // 日志类型与字体样式设置映射
QMap<LogSwitchoverType, QString> Log::logSwitchoverTypeMap = Log::initLogSwitchoverTypeMap(); // 初始化备份类型与字符的映射

QFile* Log::outLogFile = new QFile("logs/system.log");// 日志输出文件
QMap<QtMsgType, QFile*> Log::levelPaths = QMap<QtMsgType, QFile*>();// 不同级别的日志输出路径
bool Log::isDistinguishLevel = false; // 是否区分日志级别输出

QString Log::infoFormat = QString("%1 [%2] [%3] --- [%4:%5] %6: %7")
        .arg(Log::INFO_FORMAT_TIME, Log::INFO_FORMAT_LEVEL, Log::INFO_FORMAT_THREAD ,Log::INFO_FORMAT_CODE_FILE,
             Log::INFO_FORMAT_CODE_LINE, Log::INFO_FORMAT_CODE_FUNCTION, Log::INFO_FORMAT_CODE_MSG); // 日志信息格式化
QString Log::timeFormat = "yyyy-MM-dd hh:mm:ss:zzz"; // 时间格式化

QFile* Log::logParamJsonFile = new QFile("logdata/logparam.json"); // 日志参数保存json文件
LogSwitchoverType Log::logSwitchoverType = LogSwitchoverType::ALL_DAY; // 指定备份类型
long long Log::switchoverNum = 1; // 指定备份时间或大小
QDateTime Log::switchoverTime = QDateTime(); // 日志备份切换时间
bool Log::isLoadLogSwitchoverSetting = false; // 是否已经加载日志备份设置

CallBackInfoSafeList Log::pCallbacks = CallBackInfoSafeList(); // 回调函数集合

// 设置日志输出内容格式化
void Log::setFormat(QString infoFormat, QString timeFormat)
{
    if(infoFormat.trimmed().isEmpty()) {
        Log::printSystemLog("error", "设置日志格式化infoFormat为空，不进行设置");
        return;
    }
    if(!isContainInfoFormat(infoFormat)) {
        Log::printSystemLog("error", "设置日志格式化infoFormat不包含关键词："+Log::INFO_FORMAT_CODE_MSG+",不进行设置");
        return;
    }
    if(timeFormat.trimmed().isEmpty()) {
        Log::printSystemLog("error", "设置日志格式化timeFormat为空，不进行设置");
        return;
    }
    Log::infoFormat = infoFormat;
    Log::timeFormat = timeFormat;
    Log::printSystemLog("info", "设置日志输出内容格式化:"+infoFormat+",日期格式："+ timeFormat);
}

// 设置日志类型对应的字体样式
void Log::setLevelFont(QtMsgType type, std::initializer_list<int> levelFont)
{
    Log::levelFontMap.insert(type, levelFont);
    Log::printSystemLog("info", "设置日志级别"+msgTypeMap.value(type, QPair<QString, LogOutType>()).first+"样式");
}

// 设置输出路径
void Log::setOutLogPath(QString outLogPath)
{
    if(outLogPath.trimmed().isEmpty()) {
        Log::printSystemLog("error", "设置日志输出路径为空，不进行设置");
        return;
    }
    Log::outLogFile = new QFile(outLogPath);
    Log::printSystemLog("info", "设置日志输出路径："+ outLogPath);
    // 如果要区分日志级别输出，则重新调用设置是否分日志级别输出
    if(Log::isDistinguishLevel) {
        Log::setDistinguishLevel(Log::isDistinguishLevel);
    }
}

// 设置日志备份参数json存储地址
void Log::setOutLogParamJsonPath(QString logParamJsonPath)
{
    if(logParamJsonPath.trimmed().isEmpty()) {
        Log::printSystemLog("error","设置日志备份参数json存储地址为空，不进行设置");
        return;
    }
    Log::logParamJsonFile = new QFile(logParamJsonPath);
    Log::printSystemLog("info","设置日志备份参数json存储地址:"+ logParamJsonPath);
}

// 设置日志切换类型和时间或大小
void Log::setLogSwitchover(LogSwitchoverType logSwitchoverType, long long switchoverNum)
{
    if(switchoverNum < 1) {
        Log::printSystemLog("error", "设置时间或大小切换限定:"+QString::number(switchoverNum)+",小于1，不进行设置");
        return;
    }
    Log::logSwitchoverType = logSwitchoverType;
    Log::switchoverNum = switchoverNum;
    Log::printSystemLog("info","设置日志切换类型："+ Log::logSwitchoverTypeMap.value(logSwitchoverType,"")+",时间或大小切换限定："+QString::number(switchoverNum));
}

// 是否分日志级别输出
void Log::setDistinguishLevel(bool isDistinguishLevel)
{
    // 关闭已经打开的流,和删除已经设置的文件
    for(QtMsgType type : Log::levelPaths.keys()) {
        QFile* file = Log::levelPaths.value(type);
        if(file->isOpen()) {
            file->close();
        }
        if(file->exists()) {
            file->remove();
        }
    }
    // 清空映射关系
    Log::levelPaths.clear();
    // 设置是否分日志级别输出
    Log::isDistinguishLevel = isDistinguishLevel;
    // 如果分日志级别输出，则创建对应的文件和打开文件
    if(isDistinguishLevel) {
        // 关闭默认输出路径
        if(outLogFile->isOpen()) {
            outLogFile->close();
        }
        // 根据设置的输出文件路径构造不同级别的文件
        QFileInfo fileInfo = QFileInfo(Log::outLogFile->fileName());
        QString fileName = fileInfo.fileName();
        QDir dir = fileInfo.absoluteDir();
        if(!dir.exists()) {
            dir.mkdir(dir.absolutePath());
        }
        QMap<QtMsgType, QString> prefixMap = QMap<QtMsgType, QString>();
        prefixMap.insert(QtDebugMsg, "debug_");
        //一般信息文件路径
        prefixMap.insert(QtInfoMsg, "info_");
        //一般的警告文件路径
        prefixMap.insert(QtWarningMsg, "warn_");
        //严重错误文件路径
        prefixMap.insert(QtCriticalMsg, "critical_");
        //致命错误文件路径
        prefixMap.insert(QtFatalMsg, "fail_");
        for(QtMsgType type : prefixMap.keys()) {
            //调试信息文件路径
            QString filePath = dir.absoluteFilePath(prefixMap.value(type) + fileName);
            QFile* file = new QFile(filePath);
            Log::levelPaths.insert(type, file);
        }
        Log::printSystemLog("info", "已设置分日志级别输出，构建分日志文件成功");
    }
}

// 日志注册函数
void Log::messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    // 加载日志和写入相关联配置
    Log::loadLogSwitchoverSetting();

    // 下面开始解析信息
    QString txtMessage = "";
    QString nowTime = QDateTime::currentDateTime().toString(Log::timeFormat.trimmed().isEmpty() ? "yyyy-MM-dd hh:mm:ss:zzz" : Log::timeFormat);
    if(Log::msgTypeMap.contains(type)) {
        QPair<QString, LogOutType> infoPair = Log::msgTypeMap.value(type, Log::msgTypeMap.value(QtInfoMsg));
        // 格式化信息
        txtMessage = !Log::isContainInfoFormat() ? QString("%1 [%2] [%3] --- [%4:%5] %6: %7")
                                                   .arg(Log::INFO_FORMAT_TIME, Log::INFO_FORMAT_LEVEL, Log::INFO_FORMAT_THREAD, Log::INFO_FORMAT_CODE_FILE,
                                                        Log::INFO_FORMAT_CODE_LINE, Log::INFO_FORMAT_CODE_FUNCTION, Log::INFO_FORMAT_CODE_MSG)
                                                 : infoFormat;
        txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_TIME, nowTime); // 替换时间
        txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_LEVEL, infoPair.first); // 替换日志等级
        txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_CODE_FILE, context.file); // 替换代码所在文件路径
        txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_CODE_LINE, QString::number(context.line)); // 替换代码所在行数
        txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_CODE_FUNCTION, context.function); // 替换代码所在方法
        txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_CODE_MSG, msg); // 替换输出信息
        // 转换成10进制后的打印
        // QString threadInfo = QString("THREAD_ID:%1,THREAD_ADRESS:%2(%3)")
        //    .arg(QString::number(quintptr(QThread::currentThreadId())) ,QString(QThread::currentThread()->metaObject()->className()))
        //    .arg(QString::number(quintptr(QThread::currentThread())));
        // txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_THREAD, threadInfo);

        // 16进制打印
        std::stringstream threadInfoStream;
        threadInfoStream << "THREAD_ID:" << (void *)QThread::currentThreadId() << ",";
        threadInfoStream << "THREAD_ADRESS:" << QThread::currentThread()->metaObject()->className() << "(" << (void *)QThread::currentThread() << ")";
        QString threadInfo = QString::fromStdString(threadInfoStream.str());
        txtMessage = Log::replace(txtMessage, Log::INFO_FORMAT_THREAD, threadInfo); // 替换消息所在线程

        // 根据不同日志级别设置字体样式
        QString txtFontMessage = ConsoleFont::setConsoleFont(Log::levelFontMap.value(type, {ConsoleFont::DEFAULT}), txtMessage);
        // 根据输出日志类型选择输出到标准流或者是标准错误流
        if(infoPair.second == LogOutType::STANDARD_OUTPUT) {
            std::cout << txtFontMessage.toLocal8Bit().constData() << std::endl;
        } else {
            std::cerr << txtFontMessage.toLocal8Bit().constData() << std::endl;
        }
        // 写入到文件中
        writeLog(txtMessage, type);
        // 回调函数
        for(CallBackInfo callBack : Log::pCallbacks.getList()) {
            LogInfoCallBackHandler hander = callBack.hander;
            QThread* currentThread = QThread::currentThread();
            hander(type, context, currentThread, threadInfo, msg, txtMessage, callBack.context);
        }
        if(type == QtFatalMsg) {
            Log::printSystemLog("error", "致命错误，立即终止："+ msg);
            // 致命错误立即终止
            abort();
        }
    } else {
        std::cout << msg.toLocal8Bit().constData() << std::endl;
    }
}

// 注册回调函数
LogInfoCallBackHandler Log::registLogInfoCallBack(QString unique, LogInfoCallBackHandler hander, void *context)
{
    // 如果已经存在已经注册过的回调函数，则不在进行注册
    for(CallBackInfo info : pCallbacks.getList()) {
        if(info.unique == unique) {
            Log::printSystemLog("warn", "已经注册过该日志回调函数:" + unique+",不在进行注册操作");
            return hander;
        }
    }
    CallBackInfo callBackInfo(unique, hander, context);
    Log::pCallbacks.add(callBackInfo);
    Log::printSystemLog("info", "注册日志回调函数:" + unique + "成功");
    return hander;
}

// 初始化不同日志级别的输出级别标识和输出流
QMap<QtMsgType,QPair<QString, LogOutType>> Log::initMsgTypeMap()
{
    QMap<QtMsgType,QPair<QString, LogOutType>> msgTypeMap;
    //调试信息提示
    msgTypeMap.insert(QtDebugMsg,QPair<QString, LogOutType>("Debug", LogOutType::STANDARD_OUTPUT));
    //一般信息提示
    msgTypeMap.insert(QtInfoMsg,QPair<QString, LogOutType>("Info", LogOutType::STANDARD_OUTPUT));
    //一般的警告提示
    msgTypeMap.insert(QtWarningMsg,QPair<QString, LogOutType>("Waring", LogOutType::STANDARD_OUTPUT));
    //严重错误提示
    msgTypeMap.insert(QtCriticalMsg,QPair<QString, LogOutType>("Critical", LogOutType::STANDARD_ERROR_OUTPUT));
    //致命错误提示
    msgTypeMap.insert(QtFatalMsg,QPair<QString, LogOutType>("Fatal", LogOutType::STANDARD_ERROR_OUTPUT));
    return msgTypeMap;
}

// 初始化不同日志级别的字体样式参数
QMap<QtMsgType, std::initializer_list<int>> Log::initLevelFonts()
{
    QMap<QtMsgType, std::initializer_list<int>> levelColorMap;
    //调试信息字体样式
    levelColorMap.insert(QtDebugMsg,{ConsoleFont::FORE_GROUND_GREEN});
    //一般信息字体样式
    levelColorMap.insert(QtInfoMsg,{ConsoleFont::DEFAULT});
    //一般的警告信息字体样式
    levelColorMap.insert(QtWarningMsg,{ConsoleFont::FORE_GROUND_ORANGE});
    //严重错误字体样式
    levelColorMap.insert(QtCriticalMsg,{ConsoleFont::FORE_GROUND_RED, ConsoleFont::UNDER_LINE});
    //致命错误字体样式
    levelColorMap.insert(QtFatalMsg,{ConsoleFont::FORE_GROUND_RED, ConsoleFont::BOLD});
    return levelColorMap;
}

// 初始化备份类型与字符的映射
QMap<LogSwitchoverType, QString> Log::initLogSwitchoverTypeMap()
{
    QMap<LogSwitchoverType, QString> logSwitchoverTypeMap = QMap<LogSwitchoverType, QString>();
    logSwitchoverTypeMap.insert(LogSwitchoverType::ALL_DAY, "all_day");
    logSwitchoverTypeMap.insert(LogSwitchoverType::TIME_PERIOD, "time_period");
    logSwitchoverTypeMap.insert(LogSwitchoverType::FILE_SIZE, "file_size");
    return logSwitchoverTypeMap;
}

// 写入文件
void Log::writeLog(QString str, QtMsgType msgType)
{
    // 判断是否进行备份切换
    if(Log::logSwitchoverType == LogSwitchoverType::ALL_DAY || Log::logSwitchoverType == LogSwitchoverType::TIME_PERIOD) {
        // 如果当前时间超过了切换时间，则进行切换
        if(QDateTime::currentDateTime().operator >(Log::switchoverTime)) {
            // 备份日志文件
            Log::copyLogOutFile(msgType);
        }
    } else {
        long long fileSize = 0;
        if(Log::isDistinguishLevel) {
            // 计算所有日志文件大小之和
            for(QtMsgType type: Log::levelPaths.keys()) {
                QFile* msgFile = Log::levelPaths.value(type);
                fileSize = fileSize + msgFile->size();
            }
        } else {
            fileSize = Log::outLogFile->size();
        }
        // 当文件大小达到配置限制，则备份文件，因为size返回的是byte，而switchoverNum的单位是kb，所以需要乘以1024
        if(fileSize > (Log::switchoverNum*1024)) {
            // 备份日志文件
            Log::copyLogOutFile(msgType);
        }
    }
    // 写入日志到相应文件
    if(Log::isDistinguishLevel) {
        QFile* file = Log::levelPaths.value(msgType);
        if(!file->isOpen()) {
            file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
        }
        file->write((str+"\n").toUtf8());
        file->flush();
    } else {
        if(!Log::outLogFile->isOpen()) {
            Log::outLogFile->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
        }
        Log::outLogFile->write((str+"\n").toUtf8());
        Log::outLogFile->flush();
    }
}

// 备份日志文件
void Log::copyLogOutFile(QtMsgType msgType)
{
    QString nowTimeStr = QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz");
    QList<bool> copyStatus;
    QList<QtMsgType> msgTypes;
    if(Log::isDistinguishLevel) {
        // 创建备份文件夹
        QFile* file = Log::levelPaths.value(msgType);
        QFileInfo fileInfo = QFileInfo(file->fileName());
        QDir dir = fileInfo.absoluteDir();
        QString copyDirPath = dir.absoluteFilePath(nowTimeStr+"log");
        if(!dir.exists(copyDirPath)) {
            dir.mkdir(copyDirPath);
        }
        QDir copyDir(copyDirPath);
        // 将日志文件备份到备份文件夹下
        for(QtMsgType type: Log::levelPaths.keys()) {
            QFile* msgFile = Log::levelPaths.value(type);
            QFileInfo fileInfo = QFileInfo(msgFile->fileName());
            bool isSucceed = Log::copy(fileInfo.absoluteFilePath(), copyDir.absoluteFilePath(fileInfo.fileName()));
            copyStatus.append(isSucceed);
            if(isSucceed) {
                msgTypes.append(type);
            }
            Log::printSystemLog("info", "拷贝文件："+fileInfo.absoluteFilePath() + "到"+ copyDir.absoluteFilePath(fileInfo.fileName())+(isSucceed ? "成功":"失败"));
        }
    } else {
        // 创建备份文件夹
        QFileInfo fileInfo = QFileInfo(Log::outLogFile->fileName());
        QDir dir = fileInfo.absoluteDir();
        QString copyDirPath = dir.absoluteFilePath(nowTimeStr+"log");
        if(!dir.exists(copyDirPath)) {
            dir.mkdir(copyDirPath);
        }
        QDir copyDir(copyDirPath);
        // 将日志文件备份到备份文件夹下
        bool isSucceed = Log::copy(fileInfo.absoluteFilePath(), copyDir.absoluteFilePath(fileInfo.fileName()));
        copyStatus.append(isSucceed);
        Log::printSystemLog("info", "拷贝文件："+fileInfo.absoluteFilePath() + "到"+ copyDir.absoluteFilePath(fileInfo.fileName())+(isSucceed ? "成功":"失败"));
    }
    // 备份成功与否提示信息
    if(!copyStatus.contains(false)) {
        Log::printSystemLog("info", "备份日志文件成功");
    } else {
        Log::printSystemLog("error", "备份部分日志文件失败！");
    }
    // 如果备份全部成功,则清空日志文件和写入新的切换时间到日志参数配置文件
    if(Log::isDistinguishLevel) {
        for(QtMsgType type: msgTypes) {
            QFile* msgFile = Log::levelPaths.value(type);
            QFileInfo fileInfo = QFileInfo(msgFile->fileName());
            if(msgFile->resize(0)) {
                Log::printSystemLog("info", "清空日志文件内容成功："+fileInfo.absoluteFilePath());
            } else {
                Log::printSystemLog("error", "清空日志文件内容失败："+fileInfo.absoluteFilePath());
            }
        }
    } else {
        if(!copyStatus.contains(false)) {
            QFileInfo fileInfo = QFileInfo(Log::outLogFile->fileName());
            if(Log::outLogFile->resize(0)) {
                Log::printSystemLog("info", "清空日志文件内容成功："+fileInfo.absoluteFilePath());
            } else {
                Log::printSystemLog("error", "清空日志文件内容失败："+fileInfo.absoluteFilePath());
            }
        }
    }
    // 备份完成之后更新再次需要备份的时间，并写入备份参数配置文件中
    Log::writeLogParamJson();
}

// 加载备份策略的设置
void Log::loadLogSwitchoverSetting()
{
    if(Log::isLoadLogSwitchoverSetting) {
        return;
    }
    logSwitchoverSettingHander();
    Log::isLoadLogSwitchoverSetting = true;

    // 如果需要分日志输出，则先创建分日志文件
    if(Log::isDistinguishLevel) {
        for(QtMsgType type: Log::levelPaths.keys()) {
            QFile* file = Log::levelPaths.value(type);
            // 如果文件所在文件夹不存在则创建文件夹
            QFileInfo fileInfo = QFileInfo(file->fileName());
            QDir dir = fileInfo.absoluteDir();
            if(!dir.exists()) {
                dir.mkdir(dir.absolutePath());
            }
            file->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
        }
    } else {
        // 如果文件所在文件夹不存在则创建文件夹
        QFileInfo fileInfo = QFileInfo(Log::outLogFile->fileName());
        QDir dir = fileInfo.absoluteDir();
        if(!dir.exists()) {
            dir.mkdir(dir.absolutePath());
        }
        Log::outLogFile->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
    }
}

// 备份参数处理，并同步更新json文件中的数据到内存，或将设置参数写入参数文件
void Log::logSwitchoverSettingHander()
{
    if(!Log::logParamJsonFile->exists()) { // 文件不存在则创建日志备份参数json文件并将参数写入文件
        Log::writeLogParamJson();
    } else {
        if(Log::logParamJsonFile->open(QIODevice::ReadWrite | QIODevice::Text)) { // 打开文件成功则读取json文件中的配置到内存中
            QByteArray json = Log::logParamJsonFile->readAll().trimmed();
            Log::logParamJsonFile->close();
            QJsonParseError jsonError;
            QJsonDocument jsonDoc(QJsonDocument::fromJson(json, &jsonError));
            if(jsonError.error == QJsonParseError::NoError)
            {
                QJsonObject rootObj = jsonDoc.object();
                QString logSwitchoverTypeStr = rootObj.value("logSwitchoverType").toString("");
                QString switchoverNumberStr =  rootObj.value("switchoverNum").toString("");
                long long switchoverNumber = switchoverNumberStr.trimmed().isEmpty() ? 1: switchoverNumberStr.toLongLong();
                QString switchoverTimeStr =  rootObj.value("switchoverTime").toString("");
                LogSwitchoverType switchoverType;
                QDateTime switchoverTime;
                for(LogSwitchoverType type: Log::logSwitchoverTypeMap.keys()) {
                    if(Log::logSwitchoverTypeMap.value(type) == logSwitchoverTypeStr) {
                        switchoverType = type;
                        if(type == LogSwitchoverType::ALL_DAY) {
                            switchoverTime = QDateTime::fromString(switchoverTimeStr, "yyyy-MM-dd");
                        } else if(type == LogSwitchoverType::TIME_PERIOD) {
                            switchoverTime = QDateTime::fromString(switchoverTimeStr, "yyyy-MM-dd hh:mm:ss");
                        }
                        break;
                    }
                }
                Log::printSystemLog("info", "读取转换备份配置Json文件成功:"+logParamJsonFile->fileName()+",内容是："+QString(json));
                // 如果不和默认的一样，则拷贝一份，将默认的参数写入文件，这么做的目的是用户在之前设置过日志切换类型和时间或大小，后面又修改代码后又没有进行相应的设置，则需要用到默认设置
                if(switchoverType != Log::logSwitchoverType || switchoverNumber != Log::switchoverNum) {
                    Log::printSystemLog("warn", "读取配置和设置的设置过日志切换类型和时间或大小不同，写入最新配置："+logParamJsonFile->fileName());
                    Log::writeLogParamJson();
                } else {
                    Log::logSwitchoverType = switchoverType;
                    Log::switchoverNum = switchoverNumber;
                    Log::switchoverTime = switchoverTime;
                }
            } else { // 解析失败，则将内存中日志备份参数写入文件
                Log::printSystemLog("error", "转换备份配置Json文件失败:"+logParamJsonFile->fileName()+",已转为默认配置");
                Log::writeLogParamJson();
            }
        } else { // 打开失败，则将内存中日志备份参数写入文件
            Log::printSystemLog("error", "打开备份配置Json文件失败:"+logParamJsonFile->fileName()+",已转为默认配置");
            Log::writeLogParamJson();
        }
    }
}

// 写入备份参数到日志备份配置json文件中
void Log::writeLogParamJson()
{
    QDateTime nowTime = QDateTime::currentDateTime();
    QString switchoverTimeStr = "";
    if(Log::logSwitchoverType == LogSwitchoverType::ALL_DAY) {
        // 指定天数之后
        Log::switchoverTime = nowTime.addDays(Log::switchoverNum);
        switchoverTimeStr = switchoverTime.toString("yyyy-MM-dd");
    } else if(Log::logSwitchoverType == LogSwitchoverType::TIME_PERIOD) {
        // 指定秒之后
        Log::switchoverTime = nowTime.addSecs(Log::switchoverNum);
        switchoverTimeStr = nowTime.toString("yyyy-MM-dd hh:mm:ss");
    }
    QJsonObject jsonObject;//构建json对象json
    jsonObject.insert("logSwitchoverType", Log::logSwitchoverTypeMap.value(Log::logSwitchoverType, ""));
    jsonObject.insert("switchoverNum", QString::number(Log::switchoverNum));
    jsonObject.insert("switchoverTime", switchoverTimeStr);
    QJsonDocument document;
    document.setObject(jsonObject);
    QString jsonStr(document.toJson(QJsonDocument::Indented));
    // 如果文件所在文件夹不存在则创建文件夹
    QFileInfo fileInfo = QFileInfo(Log::logParamJsonFile->fileName());
    QDir dir = fileInfo.absoluteDir();
    if(!dir.exists()) {
        dir.mkdir(dir.absolutePath());
    }
    if(Log::logParamJsonFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
        Log::logParamJsonFile->write(jsonStr.toUtf8());
        Log::logParamJsonFile->flush();
        Log::logParamJsonFile->close();
        printSystemLog("info", "写入备份日志参数到"+fileInfo.absoluteFilePath()+"，成功；参数："+jsonStr);
    } else {
        printSystemLog("error", "写入备份日志参数到"+fileInfo.absoluteFilePath()+"，失败");
    }
}

// 拷贝文件
bool Log::copy(QString srcFilepPath, QString targetFilePath)
{
    QFile srcFile(srcFilepPath);
    QFile targetFile(targetFilePath);
    if(srcFile.exists()) {
        if(targetFile.exists()) {
            targetFile.remove();
        }
        return srcFile.copy(targetFilePath);
    }
    Log::printSystemLog("error", "需要备份文件不存在：" + srcFilepPath);
    return false;
}

// 替换字符串中的子字符串
QString Log::replace(QString src, QString before, QString after)
{
    if(src.isEmpty()) {
        return src;
    }
    if(!src.contains(before)) {
        return src;
    }
    QString repalceAfter = src;
    while (repalceAfter.contains(before)) {
        repalceAfter = repalceAfter.replace(src.indexOf(before), before.size(), after);
    }
    return repalceAfter;
}

// 是否包含必要的格式化信息
bool Log::isContainInfoFormat(QString mInfoFormat)
{
    QString infoFormat = Log::infoFormat;
    if(!mInfoFormat.trimmed().isEmpty()) {
        infoFormat = mInfoFormat;
    }
    if(infoFormat.trimmed().isEmpty()) {
        return false;
    }
    if(!infoFormat.contains(Log::INFO_FORMAT_CODE_MSG)) {
        return false;
    }
    return true;
}

// 日志系统信息样式及打印
void Log::printSystemLog(QString level, QString msg)
{
    if(level.trimmed().toLower() == "info") {
        QString info = ConsoleFont::setConsoleFont({ConsoleFont::FORE_GROUND_BLUE,ConsoleFont::BACK_GROUND_CYAN,ConsoleFont::BOLD}, msg);
        std::cout << info.toLocal8Bit().constData() << std::endl;
    } else if(level.trimmed().toLower() == "warn") {
        QString info = ConsoleFont::setConsoleFont({ConsoleFont::FORE_GROUND_ORANGE,ConsoleFont::BACK_GROUND_PURPLE,ConsoleFont::BOLD}, msg);
        std::cout << info.toLocal8Bit().constData() << std::endl;
    } else if(level.trimmed().toLower() == "error") {
        QString info = ConsoleFont::setConsoleFont({ConsoleFont::FORE_GROUND_RED,ConsoleFont::BACK_GROUND_GREEN,ConsoleFont::BOLD}, msg);
        std::cout << info.toLocal8Bit().constData() << std::endl;
    } else {
        QString info = ConsoleFont::setConsoleFont({ConsoleFont::FORE_GROUND_BLACK,ConsoleFont::BACK_GROUND_CYAN,ConsoleFont::BOLD}, msg);
        std::cout << info.toLocal8Bit().constData() << std::endl;
    }
}
